<?php
/**
 * | 节程 [ 节程赋能开发者，助力企业发展 ]
 * +----------------------------------------------------------------------
 *  | Copyright (c) 2020~2029 温州惊蛰网络科技有限公司 All rights reserved.
 * +----------------------------------------------------------------------
 *  | Licensed 节程并不是自由软件，未经许可不能去掉节程相关版权
 * +----------------------------------------------------------------------
 */
declare (strict_types=1);

namespace app\command;

use app\index\model\Commodity;
use app\index\model\Order;
use app\index\model\OrderCommodity;
use app\index\model\SkuInventory;
use app\index\service\InventoryService;
use app\index\util\Redis;
use Psr\Log\InvalidArgumentException;
use think\console\Command;
use think\console\Input;
use think\console\input\Argument;
use think\console\input\Option;
use think\console\Output;
use think\facade\Db;

class Cancel extends BaseCommand
{
    private $commodityId;
    private $redis;

    protected function configure()
    {
        // 指令配置
        $this->setName('cancel')
            ->setDescription('取消未支付订单');
    }

    protected function execute(Input $input, Output $output)
    {
        $this->setDb($input, $output);
    }

    protected function executeAction(Input $input, Output $output)
    {
        $select = Db::name('configuration')
            ->field('configuration,mall_id')
            ->where('type', 'tradeSetting') // order_close_time
            ->select()
            ->toArray();
        if(date('H') == 0) {
            Db::name('integral_order')->where('status', 0)->delete();
            Db::name('integral_order_commodity')->where('status', 0)->delete();
        }
        foreach ($select as $key => $value) {
            $find = $value['configuration'];
            $js = json_decode($find, true);

            if (!$js['order_is_close']) continue;
            $now = strtotime("-" . $js['order_close_time'] . "minute");
            $orders = Db::name('order')
                ->where('mall_id', $value['mall_id'])
                ->where('order_from', '0')
                ->where('status', 1)
                ->whereRaw('UNIX_TIMESTAMP(create_time) < ' . $now)
                ->field('id,mall_id')
                ->select()
                ->toArray();
            // 拼团
            $groupConfig = Db::name('configuration')->field('configuration')->where([
                'type' => 'group',
                'mall_id' => $value['mall_id']
            ])->find();
            if (!empty($groupConfig)) {
                $close_time = json_decode($groupConfig['configuration'], true)['close_time'];
                if ($close_time > 0) {
                    $group_now = strtotime("-" . $close_time . "minute");
                    $group_orders = Db::name('order')
                        ->where('mall_id', $value['mall_id'])
                        ->where('order_from', '1')
                        ->where('status', 1)
                        ->whereRaw('UNIX_TIMESTAMP(create_time) < ' . $group_now)
                        ->field('id,mall_id')
                        ->select()
                        ->toArray();
                    $orders = array_merge($orders, $group_orders);
                }
            }
            // 秒杀
            $seckillConfig = Db::name('configuration')->field('configuration')->where([
                'type' => 'seckill',
                'mall_id' => $value['mall_id']
            ])->find();
            if (!empty($seckillConfig)) {
                $seckill_time = json_decode($seckillConfig['configuration'], true)['close_time'];
                if ($seckill_time > 0) {
                    $seckill_now = strtotime("-" . $seckill_time . "minute");
                    $seckill_orders = Db::name('order')
                        ->where('mall_id', $value['mall_id'])
                        ->where('order_from', '2')
                        ->where('status', 1)
                        ->whereRaw('UNIX_TIMESTAMP(create_time) < ' . $seckill_now)
                        ->field('id,mall_id')
                        ->select()
                        ->toArray();
                    $orders = array_merge($orders, $seckill_orders);
                }
            }
            // 预售
            $presell_orders = Db::name('order')->alias('o')
                ->join('order_commodity b', 'o.id = b.order_id')
                ->join('presell_commodity c', 'b.pc_id = c.id')
                ->where('o.mall_id', $value['mall_id'])
                ->where('o.order_from', '3')
                ->where('o.status', 1)
                ->field('o.id,o.mall_id,b.pc_id,c.cancel_time,o.create_time,b.id as oc_id')
                ->select()
                ->toArray();
            foreach ($presell_orders as $pkey => $pvalue) {
                $presell_time = $pvalue['cancel_time'] > 0 ? strtotime("-" . $pvalue['cancel_time'] . "minute") : $now;
                if ((strtotime($pvalue['create_time']) - $presell_time) < 0) {
                    array_push($orders, $pvalue);
                }
            }
            $ids = array_column($orders, 'id');
            Db::name('order')
                ->where('id', 'IN', $ids)
                ->where('mall_id', $value['mall_id'])
                ->update(['status' => 12]);
            Db::name('order_commodity')
                ->where('order_id', 'IN', $ids)
                ->where('mall_id', $value['mall_id'])
                ->update(['status' => 11]);
            Db::name('agent_bill_temporary')
                ->where('order_id', 'IN', $ids)
                ->delete();
            Db::name('order_agent_profit')
                ->where('order_id', 'IN', $ids)
                ->delete();
            $orders = Db::name('order_commodity')
                ->where('order_id', 'IN', $ids)
                ->where('a.mall_id', $value['mall_id'])
                ->alias('a')
                ->join('commodity c', 'a.commodity_id = c.id', 'LEFT')
                ->join('sku_inventory s', 'a.sku_id = s.sku_id', 'LEFT')
                ->field('a.order_id,a.mall_id,a.commodity_id,a.count,(CASE WHEN c.has_sku = 1 THEN s.sell_price ELSE c.sell_price END) as price ,a.sku_id,c.inventory_type,a.status,a.id as oc_id')
                ->select();
            foreach ($orders as $v) {
                if (in_array($v['inventory_type'], [1, 2]) || (in_array($v['inventory_type'], [3]) && in_array($v['status'], [2, 3, 7]))) {
                    $this->redis = Redis::getInstance();
                    $commodityData = $this->redis->get($this->checkRedisKey('COMMODITY:' . $v['commodity_id'], $v['mall_id']));
                    if (empty($commodityData)) {
                        throw new InvalidArgumentException("商品数据不存在", HTTP_NOTACCEPT);
                    }
                    $this->commodity = json_decode($commodityData, true);
                    $this->commodityId = $v['commodity_id'];
                    $this->backInventory($v['count'],  $v['sku_id'], $v['mall_id'], $v['oc_id']);
                }
            }
        }
        // 指令输出
        $output->writeln('cancel');
    }

    private function backInventory($num, int $skuId = null, $mid, $oc_id)
    {
        if (empty($this->commodity['has_sku'])) {
            if ($this->commodity['inventory_type'] != 3) {
                Db::name('commodity')->where('id', $this->commodityId)->dec('sell', $num)->update();
            }
            $key = "COMMODITY:" . $this->commodityId . ":SELL";
            $data = [];
//            $price = $this->redis->lPop($this->checkRedisKey($key,$mid));
            $da = ["sell_price" => $this->commodity['sell_price'], "level_price" => Db::name("commodity")->find($this->commodityId)['level_price']];
            $price = json_encode($da);
            $data = array_pad($data, $num, $price);
            $this->redis->lPush($this->checkRedisKey($key, $mid), ...$data);
        } else {
            if ($this->commodity['inventory_type'] != 3) {
                Db::name('commodity')->where('id', $this->commodityId)->dec('sell', $num)->update();
                Db::name('sku_inventory')->where(['sku_id' => $skuId])->dec('sell', $num)->update();
            }
            $skuInventory=Db::name('sku_inventory')->where(['sku_id' => $skuId])->find();
            if ($skuInventory){
                $key = "COMMODITY:" . $this->commodityId . ":SKU:" . $skuId . ":SELL";
                $data = [];
//            $price = $this->redis->lPop($this->checkRedisKey($key,$mid));
                $da = ["sell_price" => $skuInventory['sell_price'], "level_price" => $skuInventory['level_price']];
                $price = json_encode($da);
                $data = array_pad($data, $num, $price);
                $this->redis->lPush($this->checkRedisKey($key, $mid), ...$data);
            }

        }
        $this->incStock($oc_id);
        return true;
    }

    /**
     * 加库存
     * @param $value
     * @throws
     */
    private function incStock($oc_id)
    {
        $oc = Db::name('order_commodity')->find($oc_id);
        if ($oc['sc_id'] > 0) {
            $act_name = "seckill";
            $act_id = 'sc_id';
        }
        if ($oc['pc_id'] > 0) {
            $act_name = 'presell';
            $act_id = 'pc_id';
        }
        if (isset($act_name)) {
            // 拼团库存
            if (is_null($oc['sku_id'])) {
                Db::name($act_name.'_commodity')
                    ->where('id', $oc[$act_id])
                    ->inc("activity_stock", $oc['count'])->update();
            } else {
                Db::name($act_name.'_commodity_sku')
                    ->where($act_id, $oc[$act_id])
                    ->where('sku_id', $oc['sku_id'])
                    ->inc("activity_stock", $oc['count'])->update();
            }
        }
    }

    private function checkRedisKey($key, $mid)
    {
        return "MALL:" . $mid . ":" . $key;
    }


}
